import { useKeyPress as useKeyPressEffect } from 'ahooks';
import { useCallback } from 'react';
import { Node, useKeyPress } from 'reactflow';
import { useContextSelector } from 'use-context-selector';

import { t } from '@/locales/i18n';
import { getWorkflowStore, WorkflowContext } from '@/pages/app/detail/components/Workflow/context';
import { getNanoid } from '@/pages/chat/tools/tools';
import { FlowNodeTypeEnum } from '@/types/workflow/constant';
import { FlowNodeItemType } from '@/types/workflow/node';

import { useCopyData } from '../use-copydata';

import { useWorkflowUtils } from './useUtils';

export const useKeyboard = () => {
  const { setNodes, mouseInCanvas } = useContextSelector(WorkflowContext, (v) => v);
  const { copyData } = useCopyData();
  const { computedNewNodeName } = useWorkflowUtils();

  const isDowningCtrl = useKeyPress(['Meta', 'Control']);

  const hasInputtingElement = useCallback(() => {
    const { activeElement } = document;

    if (activeElement) {
      const tagName = activeElement.tagName.toLowerCase();
      const className = activeElement.className.toLowerCase();
      if (tagName === 'input' || tagName === 'textarea') return true;
      if (className.includes('prompteditor')) return true;
      if (className.includes('contenteditable')) return true;
    }

    return false;
  }, []);

  const onCopy = useCallback(async () => {
    if (hasInputtingElement()) return;
    const { nodes } = await getWorkflowStore();

    const selectedNodes = nodes.filter(
      (node) => node.selected && !node.data?.isError && node.data?.unique !== true,
    );
    if (selectedNodes.length === 0) return;
    copyData(JSON.stringify(selectedNodes), t('core.workflow.Copy node'));
  }, [copyData, hasInputtingElement]);

  const onParse = useCallback(async () => {
    if (hasInputtingElement()) return;
    const copyResult = await navigator.clipboard.readText();
    try {
      const parseData = JSON.parse(copyResult) as Node<FlowNodeItemType, string | undefined>[];
      // check is array
      if (!Array.isArray(parseData)) return;
      // filter workflow data
      const newNodes = parseData
        .filter(
          (item) =>
            !!item.type && item.data?.unique !== true && item.type !== FlowNodeTypeEnum.loop,
        )
        .map((item) => {
          const nodeId = getNanoid();
          return {
            // reset id
            ...item,
            id: nodeId,
            data: {
              ...item.data,
              name: computedNewNodeName({
                templateName: item.data?.name || '',
                flowNodeType: item.data?.flowNodeType || '',
                pluginId: item.data?.pluginId,
              }),
              nodeId,
              parentNodeId: undefined,
            },
            position: {
              x: item.position.x + 100,
              y: item.position.y + 100,
            },
          };
        });

      // Reset all node to not select and concat new node
      setNodes((prev) =>
        prev
          .map((node) => ({
            ...node,
            selected: false,
          }))
          // @ts-ignore
          .concat(newNodes),
      );
    } catch (error) {
      console.error(error);
    }
  }, [computedNewNodeName, hasInputtingElement, setNodes]);

  useKeyPressEffect(['ctrl.c', 'meta.c'], (e) => {
    if (!mouseInCanvas) return;
    onCopy();
  });
  useKeyPressEffect(['ctrl.v', 'meta.v'], (e) => {
    if (!mouseInCanvas) return;
    onParse();
  });
  useKeyPressEffect(['ctrl.s', 'meta.s'], (e) => {
    e.preventDefault();
  });

  return {
    isDowningCtrl,
  };
};

export default useKeyboard;
